package network;

import java.io.*;
import java.net.*;
import java.util.*;

/**
 * Класс, получающий флаги у эксплойта с stdout и отправляющий их на сервер.
 * Запускается Moderator'ом по одному на команду.
 */

public class TeamCurator extends Thread
{

	// ----------------- CONFIGURATION ----------------

	public static String exploitFileName = "zero.pl";
	public static String exploitName = "ZeroExploit";
	public static String efServerIp = "10.15.1.130";
	public static int efServerPort = 62674;
	public static String vulnBoxSuff = "3";
	public static int exploitRestartDelay = 10000;
	public static int flagWaitDelay = 5000;
	public static int timesToWaitFlag = 4;

	// not implemented yet :)
	public static String logFileName = "logs/" + exploitName + ".txt";

	// ------------------------------------------------

	private Process exploitProcess;
	private Socket efServerSock;

	public String teamIp;
	public String teamName;
	public Set<String> sent; // for tests

	/**
	 * Конструктор получает имя команды и адрес подсети /24, где находится
	 * уязвимая машина
	 */

	public TeamCurator(String ip, String name)
	{
		teamName = name;
		teamIp = ip + vulnBoxSuff;
	}

	@Override
	public void run()
	{
		System.out.println("Team " + teamName + " <=> " + teamIp + " started!");
		efServerSock = createSocket(efServerIp, efServerPort);
		sent = new HashSet<String>();
		if (efServerSock != null)
		{
			BufferedWriter efServerWriter = null;
			BufferedReader exploitReader = null;

			try
			{
				efServerWriter = new BufferedWriter(new OutputStreamWriter(
						efServerSock.getOutputStream()));
				efServerWriter.write(exploitName + " " + teamIp + "\r\n");
				sent.add(exploitName + " " + teamIp);
			} catch (IOException e1)
			{
				System.err
						.println("ERROR! IO exception in getting buffer from efServerSock!");
				System.err.println(e1.getMessage());
				try
				{
					efServerSock.close();
				} catch (IOException e)
				{
					return;
				}
				return;
			}

			while (true)
			{// exploit restarting
				System.out.println("Starting exploit " + exploitFileName
						+ " for team " + teamName + "(" + teamIp + ")");
				Runtime runtime = Runtime.getRuntime();
				try
				{
					exploitProcess = runtime.exec(exploitFileName + " "
							+ teamIp);
					exploitReader = new BufferedReader(new InputStreamReader(
							exploitProcess.getInputStream()));
					Scanner scanner = new Scanner(exploitReader);
					int noFlagTimes = 0;
					while (true)
					{// getting flags from process
						String flag;
						if (scanner.hasNext())
						{
							noFlagTimes = 0;
							flag = scanner.next();
							System.out.println(teamName + "(" + teamIp
									+ ") -> " + flag);
							try
							{
								efServerWriter.write(flag + "\r\n");
								efServerWriter.flush();
								sent.add(flag);
							} catch (IOException e)
							{
								System.err
										.println("ERROR! IO exception in sending flag to efServer");
								System.err.println(e.getMessage());
								exploitProcess.destroy();
								try
								{
									efServerSock.close();
								} catch (IOException ex)
								{

								}
								return; // we need to stop tread - moderator
										// would restart us
							}

						} else
						{
							noFlagTimes++;
							try
							{
								System.out.println("Exploit terminated with: "+exploitProcess.exitValue());
								break;
							}
							catch (IllegalThreadStateException e) {
								System.out.println("Process has been terminated");
							}
							if (noFlagTimes < timesToWaitFlag)
							{
								sleep(flagWaitDelay);

							} else
							{
								break; // it's time to kill this exploit - too
										// long time to work
							}
						}
					}

					System.err
							.println("Exploit says nothing for too long time("
									+ flagWaitDelay * timesToWaitFlag
									+ " ms) Killing him if he is alive!");
					exploitProcess.destroy();
					/*
					try
					{
						efServerSock.close();
					} catch (IOException e)
					{

					}
 					*/
					sleep(exploitRestartDelay);

				} catch (IOException e1)
				{
					System.err
							.println("ERROR! IO exception in creating/processing exploit");
					System.err.println(e1.getMessage());
				} catch (InterruptedException e)
				{
					System.err
							.println("TeamCurator was interrupted when sleeping! What does it mean?");
					System.err.println(e.getMessage());
				}

			}
		} else
		{
			System.err.println("Not connected to efServer. Exiting thread");
		}
	}

	/**
	 * Создает сокет для соединения с ef-сервером, чтобы сливать туда флаги.
	 * 
	 * @return Socket если случилась неприятность вернет null и напишет в stderr
	 */
	private Socket createSocket(String ip, int port)
	{
		Socket efServerSock = null;
		try
		{
			efServerSock = new Socket(InetAddress.getByName(ip), port);
		} catch (UnknownHostException e)
		{
			System.err.println("Unknown host " + ip);
			System.err.println(e.getMessage());
		} catch (IOException e)
		{
			System.err.println("IO problem creating socket to efServer " + ip);
			System.err.println(e.getMessage());
		}
		return efServerSock;
	}

	public void interrupt()
	{
		exploitProcess.destroy();
		try
		{
			efServerSock.close();
		} catch (IOException e)
		{

		}
	}

}
